Examples how to visualize IMC images via bbwidgets & imctools

This show a simple example how to load a single image.

It uses imctools: https://github.com/BodenmillerGroup/imctools and bbwidgets: https://github.com/BodenmillerGroup/bbwidgets

Further it shows a more complex example, how to load a folder containing IMC ome folders & using all the metadata to lable the acquisitions.

How to load and view 1 .ome.tiff

In [1]:
from imctools.io import ometiffparser
import bbwidgets
In [2]:
fn_ome = '/home/vitoz/Data/Analysis/201805_cp3_processing/ometiff/20170906_FluidigmONfinal_SE/20170906_FluidigmONfinal_SE_s0_p2_r3_a3_ac.ome.tiff'
In [3]:
imc_ac = ometiffparser.OmetiffParser(fn_ome).get_imc_acquisition()
In [4]:
bbwidgets.view_multichannel([imc_ac.data], channel_names=imc_ac.channel_labels)
/home/vitoz/miniconda2/envs/spheroid_env/lib/python3.7/site-packages/traittypes/traittypes.py:101: UserWarning: Given trait value dtype "float32" does not match required type "float64". A coerced copy has been created.
  np.dtype(self.dtype).name))

How to load and view 1 .ome.tiff folder & metadata

In [5]:
import bbwidgets
import pathlib
import pandas as pd
import numpy as np
import re

from imctools.io import ometiffparser
from imctools.scripts import exportacquisitioncsv
import imctools.io.mcdxmlparser as mcdmeta
In [6]:
class variables:
    """
    This contains variables that should not be changed
    """
    COL_FN = 'filename'
    COL_PATH = 'path'
    COL_IMCAC = 'imc_ac'
    COL_VALIDAC = 'has_all_channels'
    COL_IMGS = 'images'
    COL_ACSESSION = exportacquisitioncsv.COL_ACSESSION
    COL_SLIDEID = mcdmeta.SLIDEID
    COL_PANORAMAID = mcdmeta.PANORAMAID
    COL_ACQUISITIONROIID = mcdmeta.ACQUISITIONROIID
    COL_ACQUISITIONID =  mcdmeta.ACQUISITIONID
    COL_PANORAMA = mcdmeta.PANORAMA
    COL_ACQUISITIONROI = mcdmeta.ACQUISITIONROI
    COL_ACQUISITION = mcdmeta.ACQUISITION
    re_fn_meta = re.compile(f'(?P<{COL_ACSESSION}>.*)_s(?P<{COL_SLIDEID}>[0-9]+)_p(?P<{COL_PANORAMAID}>[0-9]+)_r(?P<{COL_ACQUISITIONROIID}>[0-9]+)_a(?P<{COL_ACQUISITIONID}>[0-9]+)_ac.*')
    meta_types = {COL_ACSESSION: str,
                  COL_SLIDEID: int,
                 COL_PANORAMAID: int,
                 COL_ACQUISITIONROIID: int,
                 COL_ACQUISITIONID: int}
V = variables
In [7]:
class configuration:
    """
    This contains configurations that likely need to be changed/adapted
    """
    # the folder containing other ome folders
    fol_ome = pathlib.Path('/home/vitoz/Data/Analysis/201805_cp_segmentation_example/ometiff/')
C = configuration

Load the data & metadata

Memory map all the acquisitions

In [9]:
dat_acs = pd.DataFrame({V.COL_PATH: list(C.fol_ome.glob('*/*.ome.tiff'))})
In [10]:
dat_acs[V.COL_IMCAC] = dat_acs[V.COL_PATH].map(lambda fn: ometiffparser.OmetiffParser(fn).get_imc_acquisition())

Get the metadata

-> This loads all the metadata csv from the ome folder

In [12]:
dat_acmeta = exportacquisitioncsv._read_and_concat(C.fol_ome,suffix=f'_{mcdmeta.ACQUISITION}_meta.csv',idname=mcdmeta.ACQUISITIONID).rename(columns={mcdmeta.DESCRIPTION: mcdmeta.ACQUISITION})
dat_panometa = exportacquisitioncsv._read_and_concat(C.fol_ome,suffix=f'_{mcdmeta.PANORAMA}_meta.csv',idname=mcdmeta.PANORAMAID).rename(columns={mcdmeta.DESCRIPTION: mcdmeta.PANORAMA})
dat_roimeta = exportacquisitioncsv._read_and_concat(C.fol_ome,suffix=f'_{mcdmeta.ACQUISITIONROI}_meta.csv',idname=mcdmeta.ACQUISITIONROIID).rename(columns={mcdmeta.DESCRIPTION: mcdmeta.ACQUISITIONROI})

Parse the metadata from the filenames

In [13]:
def split_names(x, re_comp):
    c = re_comp
    m = c.match(x)
    g = m.groups() 
    return pd.Series({l: g[i-1] for l, i in c.groupindex.items()}, name=x.index)
In [14]:
dat_acs[V.COL_FN] = dat_acs[V.COL_PATH].map(lambda x: x.stem)

dat_acs = dat_acs.join(dat_acs[V.COL_FN].apply(split_names, re_comp=V.re_fn_meta))
dat_acs = dat_acs.astype(V.meta_types)

Visualize the acquisitions

In [15]:
def get_img_from_imcac(imcac, metals):
    """
    A helper function to get the image stacks with the right metals
    """
    return [imcac.get_img_by_metal(m) for m in metals]

Determine a reference acquisition to choos the channel labels from

In [16]:
ref_idx = 8

ref_ac = dat_acs[V.COL_IMCAC][ref_idx]
metals = ref_ac.channel_metals
# derive nicer labels
channel_labels = [f'{l} - {m}'  for l, m in zip(ref_ac.channel_labels, ref_ac.channel_metals)]

print(f'Reference Acquisition: {ref_ac.image_ID}')
Reference Acquisition: 20170906_FluidigmONfinal_SE_s0_p2_r3_a3_ac.ome.tiff

Assert that all the acquisitions need to have the reference acquisitions channels

In [17]:
dat_acs[V.COL_VALIDAC] = dat_acs[V.COL_IMCAC].map(lambda ac: set(ref_ac.channel_metals).issubset(ac.channel_metals))
In [18]:
# filter for valid acquisitions
dat = (dat_acs
       .query(f'{V.COL_VALIDAC}==True')
       .merge(dat_acmeta)
       .merge(dat_panometa)
      )
# generate the images
imgs = [get_img_from_imcac(ac, metals=metals) for ac in dat[V.COL_IMCAC].values]
# create labels based on metadata
labels = dat.apply(lambda row: f'{row[V.COL_ACSESSION].split("_")[1]}\n P: {row[V.COL_PANORAMA]} \n A: {row[V.COL_ACQUISITION]}', axis=1)
In [19]:
bbwidgets.view_multichannel(imgs, image_names=labels, channel_names=channel_labels)

Show only acquisitions from a certain site

In [20]:
site = ['Site4']
In [21]:
# filter for valid acquisitions
dat = (dat_acs
       .query(f'{V.COL_VALIDAC}==True')
       .merge(dat_acmeta)
       .merge(dat_panometa)
       .query(f'{V.COL_PANORAMA} == {site}')
      )
# generate the images
imgs = [get_img_from_imcac(ac, metals=metals) for ac in dat[V.COL_IMCAC].values]
# create labels based on metadata
labels = dat.apply(lambda row: f'{row[V.COL_ACSESSION].split("_")[1]}\n P: {row[V.COL_PANORAMA]} \n A: {row[V.COL_ACQUISITION]}', axis=1)
In [22]:
bbwidgets.view_multichannel(imgs, image_names=labels, channel_names=channel_labels)
In [ ]: